//
//  xlx_action.c
//  指令处理
//
//  data 2024/8/20.
//

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_log.h"
#include "esp_random.h"

#include "xlx_define.h"
#include "xlx_core.h"
#include "xlx_action.h"
#include "xlx_wakeup_save.h"
#include "uart1_cmd.h"

static const char* TAG = "Action";

#ifdef _MSC_VER
    #define strcasecmp _stricmp
    #define strncasecmp _strnicmp
#endif

// 用来做倒计时功能 
typedef struct{
    char enable;// 1开启，0关闭 
    int16_t time;// 剩余倒计时秒数 
    int32_t value;// 自定义携带值 
}DelayCountDown;

typedef struct{
    // 指令名字 
    char *name;
    // 指令对应函数指针,1:成功 0：失败 
    void (*func)(xlx_action_data *data);
}ActionFunc;

// 缓存区，用来放回复web端的内容 
static char g_pri_web_rspbuf[AT_CMD_OUT_BUFF_SIZE_MAX] = {0};
// 缓存区，用来放回复短信的内容 
static char g_pri_sms_rspbuf[AT_CMD_OUT_BUFF_SIZE_MAX] = {0};

// 开始ota倒计时 
DelayCountDown g_pri_fota_countdown = {0};

// 关机倒计时 
DelayCountDown g_pri_power_countdown = {0};

// 重启
DelayCountDown g_pri_restart_countdown = {0};

// 指令列表配置 
static ActionFunc action_list[] = {
    {"Version",xlx_action_version},
    {"demo",xlx_action_demo},
    {"FileTest",xlx_action_file_test},

    {"Login",xlx_action_login},

    {"Reset",xlx_action_reset},
    {"Restart",xlx_action_restart},
    {"TaskList",xlx_action_tasklist},

    {"SetPwd",xlx_action_setpwd},
    {"SetServer",xlx_action_setserver},

    {"SetGpsCfg",xlx_action_setgpscfg},
    {"GetNextWakeup", xlx_action_GetNextWakeup},
    {"SetHeartbeat",xlx_action_setHeartbeat},

    {"ShowLog",xlx_action_showlog},
    {"TestMode",tutucation_testmode},

    {"CheckUpgrade",xlx_action_checkupgrade},
    {"ClearCfg",xlx_action_clearcfg},
    {"Close",xlx_action_close},
    {"CloseList",xlx_action_closelist},
    {"DeviceInfo",xlx_action_deviceinfo},
    {"DeviceTime",xlx_action_devicetime},
    {"EnableNet",xlx_action_enablenet},
    {"FlyMode",xlx_action_flymode},
    {"Find",xlx_action_findcar},
    {"GetAudioDbmInfo",xlx_action_getaudiodbm},
    {"GetBattery",xlx_action_getbattery},
    {"GetGps",xlx_action_getgps},
    {"GetGpsInfo",xlx_action_getgpsinfo},
    {"GetICCID",xlx_action_geticcid},
    {"GetSOS",xlx_action_getsos},
    {"GetWhite",xlx_action_getwhite},
    {"LightInfo",xlx_action_lightinfo},
    {"NetLog",xlx_action_netlog},
    {"NowGps",xlx_action_nowgps},
    {"Open",xlx_action_open},
    {"OpenList",xlx_action_openlist},
    {"Poweroff",xlx_action_poweroff},
    {"Poweron",xlx_action_poweron},
    {"PowerSwitch",xlx_action_powerswitch},
    {"RecordAudio",xlx_action_recordaudio},
    {"Refresh",xlx_action_refresh},

    {"HardPowerOff",xlx_action_hardpoweroff},
    {"RtmpOpen",xlx_action_rtmpopen},
    {"RtmpClose",xlx_action_rtmpclose},
    {"RtmpInfo",xlx_action_rtmpinfo},
    {"RtmpValid",xlx_action_rtmpvalid},

    {"RtmpPull",xlx_action_rtmppull},
    {"RtmpStopPull",xlx_action_RtmpStopPull},    

    {"ShakeGps",xlx_action_shakegps},
    {"SetApn",xlx_action_setapn},
    {"SetAudioBitRate",xlx_action_setaudiobitrate},
    {"SetAudioDbm",xlx_action_setaudiodbm},
    {"SetAudioDbmH",xlx_action_setaudiodbmh},
    {"SetAudioFile",xlx_action_setaudiofile},
    
    {"SetLowVoltage",xlx_action_lowvoltage},

    {"SetShakeST",xlx_action_setshake},
    {"SetSOS",xlx_action_setsos},
    {"SetSpeed",xlx_action_setspeed},
    {"SetUploadTurn",xlx_action_setuploadturn},
    {"SetWhite",xlx_action_setwhite},
    
    {"SwitchMode",xlx_action_switchmode},
    {"TestMicIrq",xlx_action_testmicirq},
    {"TestMicStart",xlx_action_testmicstart},
    {"TestMicStop",xlx_action_testmicstop},
    
    {"TestCan",xlx_action_testcan},
    {"TestShake",xlx_action_testshake},
    
    {"Weakup",xlx_action_wekup},
    {"WriteImei",xlx_action_writeimei},
    {"GpsLog",xlx_action_gpslog},
    {"GameOver",xlx_action_gameover},
    {"GsensorLog",xlx_action_gsensorlog},
    {"CheckRf",xlx_action_testcheckrf},
    {"WifiCtrl", xlx_action_testwifi},
    

    // Kenglee 	

    {"GetTime", xlx_action_GetTime},
    {"GetStampToTime", xlx_action_GetStampToTime},
    {"SyncNtp", xlx_action_SyncNtpTime},
    //{"ScanWifi", xlx_action_ScanWifi},
    {"SetLed", xlx_action_SetLed},
    
    {"GetWakeupSrc", xlx_action_GetWakeupSrc},
    {"ReadSensorReg", xlx_action_ReadSensorReg},
    {"WriteSensorReg", xlx_action_WriteSensorReg},
    {"Callout", xlx_action_Callout},
    {"Callend", xlx_action_Callend},
    {"PlayTTS", xlx_action_PlayTTS},
    {"StopTTS", xlx_action_StopTTS},
    {"SendSMS", xlx_action_SendSMS},    
    {"TestWifiscan", xlx_action_TestWifiscan},    
    {"hourRemind", xlx_action_HourRemind},    
    {"AutoFly", xlx_action_AutoFlay},    
    {"volumeControl", xlx_action_VolumeControl},    
    {"SetSysPmWork", xlx_action_SetSysPmWork},    
    {"SetSpeaker", xlx_action_SetSpeaker},    
    {"RtmpParams", xlx_action_RtmpParams},      
    {"ShowPullPackLog", xlx_action_showpullpacklog},    
    {"LogShowRtmpFileData", xlx_action_LogShowRtmpFileData},    
    {"SetOpenGpsInterval", xlx_action_SetOpenGpsInterval},    
    {"SetPullRtmpBuffSize", xlx_action_SetPullRtmpBuffSize},
    {"SetSosCall", xlx_action_SetSosCall},

    {"SetSosThread", xlx_action_SetSosThreadState},
    {"SetAllEvent", xlx_action_SetAllEvent},
    {"Set1sTimer", xlx_action_Set1sTimer},
   
    // gpio control : read/write
    {"GpioRW", xlx_action_GpioRW},    
    {"PlayKeyTTS", xlx_action_PlayKeyTTS},  //　播放按键，用于设置
    {"AtCmd",xlx_action_atcmd},
    
    
    {"GetHeap",xlx_action_GetHeap},
    {"", NULL}
};


#if 0
extern char xlx_device_imei[];
extern int xlx_factory_test_mode;
extern int xlx_factory_shake_counter;
extern int xlx_factory_mic_irq;
extern int xlx_show_logger;
extern int xlx_gps_logger;
extern int xlx_gsensor_logger;//是否开启gsensor日志,上传服务器
#endif

void xlx_action_replay_data(xlx_action_data *data);

/**
 * 根据函数名，动态调用
 * @param func_name 函数名称
 * @param t 指令从什么途径来的
 * @param actionid 任务id
 * @param argc 参数个数
 * @param argv 参数列表
 */
static void xlx_action_callfunc(const char *func_name, xlx_action_data *data){
    int j = 0;
    char b = 0;
    int offset = 0;

    for(j = 0;func_name;j++){
        if(action_list[j].func){
            
            if(*func_name == '@'){
                // 如果是@开头的，则收到消息不需要回复 
                data->reply = ACTION_REPLY_NO;
                offset = 1;
            }else if (*func_name == '#'){
                // 如果是#开头的，则收到消息需要使用平台进行回复 
                // 并且最后一个为uint16_t 的id标识 
                data->reply = ACTION_REPLY_WEB;
                offset = 1;
            }else{
                data->reply = ACTION_REPLY_YES;
            }

            // TUTU_LOGI(TAG, "action:%s, list[%d]:%s(offset=%d)",func_name, j, action_list[j].name, offset);

            if(strcasecmp(action_list[j].name,func_name+offset) == 0){
                b = 1;
                data->actionname = action_list[j].name;
                TUTU_LOGI(TAG, "[ffly] call string action:%s",func_name);
                action_list[j].func(data);
                xlx_action_replay_data(data);
                // g_tutuparam.up_sync_status_counter = 3;
                return;
            }
        }else{
            break;
        }
    }

    if(b == 0 && data->t == ACTION_TYPE_WEB){
        // const char *rsp = "unknow function\n";
        // web 暂时频闭
        //  tutuapi_send_stringaction(data->actionid,rsp,strlen(rsp));
    } else if (b == 0 && data->t == ACTION_TYPE_AT) {
        if (data->outbuf) snprintf(data->outbuf, AT_CMD_OUT_BUFF_SIZE_MAX, "Unknow function: %s", func_name);
    }
}


/**
 * at指令数据处理入口
 */
void xlx_action_process_at_data(char *outresult,int argc,char **argv){
    if(argc > 0){
        xlx_action_data data = {0};
        data.reply = ACTION_REPLY_NO;
        data.t = ACTION_TYPE_AT;
        data.actionid = 0;
        data.tel = 0;
        data.argc = argc;
        data.argv = argv;
        data.outbuf = outresult;

        // 匹配函数，并调用 
        xlx_action_callfunc(argv[0],&data);
    } else {
        TUTU_LOGI(TAG, "argc------->%d", argc);
    }
}

/**
 * 指令数据处理入口
 * @param actionid 任务id
 * @param data 指令内容
 * @param len 指令内容长度
 */
void xlx_action_process_data(ACTION_TYPE t,unsigned short actionid,const char *tel,const char *data,int len){
    int i = 0;
    int argc = 0;
    char *argv[64] = {0};
    char buf[512] = {'\0'};
    char *start = buf;
    char c = 0;
    if(len > 511){
        return;
    }
cc:
    for(;i < len;i++){
        buf[i] = *(data+i);
        c = buf[i];
        if(c == ',' || c == '\n'){
            buf[i] = '\0';
            if(argc >= 64){
                return;
           	}
           	argv[argc] = start;
            start = buf+i+1;
            argc++;
            if(c == '\n'){
                break;
            }
	    }else if (i == len - 1){
            argv[argc] = start;
            argc++;
        }
    }

    if(argc > 0){
        xlx_action_data data = {0};
        data.t = t;
        data.actionid = actionid;
        data.tel = tel;
        data.argc = argc;
        data.argv = argv;
        
        if(t == ACTION_TYPE_WEB){
           data.outbuf = g_pri_web_rspbuf; 
        }else if(t == ACTION_TYPE_SMS){
            data.outbuf = g_pri_sms_rspbuf;
        }

        // 匹配函数，并调用 
        xlx_action_callfunc(argv[0],&data);
    }

    if(i+1 < len){
        argc = 0;
        i++;
        goto cc;// 继续处理下一个action 
    }
    
    argc = 0;
}

void xlx_action_replay_data(xlx_action_data *data){
    // 需要使用平台回复 
    if(data->argc > 1 && data->reply == ACTION_REPLY_WEB){
        int usercode = atoi(data->argv[data->argc - 1]);
        data->t = ACTION_TYPE_WEB;

        if(usercode > 0){
            strcat(data->outbuf,",");
            strcat(data->outbuf,data->argv[data->argc - 1]);
            strcat(data->outbuf,"\n");
        }
    }

// 先屏蔽
    if(data->reply != ACTION_REPLY_NO){
        // 回复平台 
        if(data->t == ACTION_TYPE_WEB){
            tutuapi_send_stringaction(data->actionid,data->outbuf,strlen(data->outbuf));
        }
    }
}

/**
 * 回复
 */
static void xlx_action_reply(int success,xlx_action_data *data){
    if(strlen(data->actionname) > 100){
        TUTU_LOGI(TAG, "!!!action name:%s length > 100!!!  %s %d",data->actionname, __func__,__LINE__);
        return;
    }

    if(success == 1){
        sprintf(data->outbuf,"%s ok\n",data->actionname);
    }else{
        sprintf(data->outbuf,"%s failt\n",data->actionname);
    }
    
    // if (xlx_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
}

//系统版本

// 设备版本信息 
void xlx_action_version(xlx_action_data *data){   
    char *versionstr = get_current_outside_sw_version();
    if(strlen(versionstr) > 127){
        TUTULOG("tutuaction_version rsp length > 127");
        return;
    }
    TUTUSnprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Version %s,%s,id:%s\n",versionstr,get_CHECKCODE(),tutu_device_imei);
    if (tutu_factory_test_mode) TUTULOG("%s", data->outbuf);    
}

// 恢复出厂设置 
void xlx_action_demo(xlx_action_data *data){
    int success = 1;
    xlx_action_reply(success,data);
}


/*
 * 测试文件操作
 * 格式：   FileTest,op_id,param1,param2
 * op_id:
 *          0:  列出文件
 *          1:  按文件名读出内容
 *          2:  按文件名写入输入，如果后面不带内容就写入一段随机大小的数据，否则写带的内容
 *          3:  按文件名 删除文件
*/
void xlx_action_file_test(xlx_action_data *data){
    int success = 0;

    if(data->argc > 0){
        if (0 == atoi(data->argv[1])){
            g_tutufile.list_dir(data->outbuf);
            return;            
        }
        else {
            if(data->argc > 1){

                if (1 == atoi(data->argv[1])){      // 写入
                    TUTU_LOGI(TAG,"%s@line%d",__FUNCTION__,__LINE__);

                    // 如果后面有内容，则写入内容
                    unsigned long int buff_size;

                    if(data->argc > 3){ // 带了参数
                        buff_size = strlen(data->argv[3]);
                        sprintf(data->outbuf,"file %s write %s(%ldbytes)",
                            data->argv[2], 
                            (g_tutufile.write_file(data->argv[2], data->argv[3], buff_size)?"OK":"FAIL"),
                            buff_size);                    
                    }
                    else {          // 未带参数,随机产生
                        // 一个随机大小到数据包     
                        buff_size = esp_random();
                        char * queue_buff;
                        buff_size %= 128;
                        buff_size += 1; // 防止为0

                        TUTU_LOGI(TAG,"%s@line%d",__FUNCTION__,__LINE__);

                        queue_buff = malloc(buff_size);
                        if(queue_buff){
                            memset(queue_buff, 0x30+(buff_size%10), buff_size);
                            queue_buff[buff_size-1]= 0x00;        

                            g_tutufile.write_file(data->argv[2], queue_buff, buff_size);
                            free(queue_buff);
                        }
                        else {  
                            TUTU_LOGE(TAG,"malloc ERROR(size=%ld) %s@line%d", buff_size ,__FUNCTION__,__LINE__);
                        }
                    }
                }
                else if (2 == atoi(data->argv[1])){      // 读入{

                    unsigned long file_size = AT_CMD_OUT_BUFF_SIZE_MAX-16;
                    char buff[AT_CMD_OUT_BUFF_SIZE_MAX-16] ={0};

                    TUTU_LOGE(TAG,"size=%ld", g_tutufile.get_file_size(data->argv[2]));
                    g_tutufile.read_file_ex(data->argv[2], (char *)buff, &file_size);
                    sprintf(data->outbuf,"read file(%ldbytes)%s:%s", file_size, data->argv[2], (char *)buff);
                    return;
                }
                else if (3 == atoi(data->argv[1])){      // 删除{
                    sprintf(data->outbuf,"(fileDel)%s, code= %d",data->argv[2],  g_tutufile.my_delfile(data->argv[2]));
                    return;
                }                
            }
        }
        success = 1;
    }

    xlx_action_reply(success,data);
}


// 检查短信是否登陆，是否有权限 
static char xlx_action_check_permission(ACTION_TYPE t){
    if(t == ACTION_TYPE_SMS){
        // TUTU_LOGI(TAG, "GET_UTC_timestamp %s:%d", __FUNCTION__, __LINE__);
        if(g_tutuparam.is_login_msm == 1 && g_tutuos.get_utc_timestamp() < g_tutuparam.login_action_time){
            return 1;
        }
        return 0;
    }
    return 1;
}

// 登录鉴权 
void xlx_action_login(xlx_action_data *data){
    int success = 0;

    if(data->argc >= 3){
        if(strcmp(g_tutuconfig.device_pwd,data->argv[1]) == 0 ){
            
            int second = atoi(data->argv[2]) * 60;
            
            // 登陆成功 
            g_tutuparam.is_login_msm = 1;
            // 设置权限有效期截至时间 
            // TUTU_LOGI(TAG, "GET_UTC_timestamp %s:%d", __FUNCTION__, __LINE__);
            g_tutuparam.login_action_time =  g_tutuos.get_utc_timestamp() + second;

            success = 1;
        }else{
            g_tutuparam.is_login_msm = 0;
        }
    }

    xlx_action_reply(success,data);
}

// 修改密码,短信平台需要先login,平台可以强制修改 
void xlx_action_setpwd(xlx_action_data *data){
    int success = 0;

    if(data->argc > 0){
        if(xlx_action_check_permission(data->t) == 1){
            memset(g_tutuconfig.device_pwd,0,6);
            xlx_strcopy(g_tutuconfig.device_pwd,6,data->argv[1]);
            tutu_save_config_flag = 1;

            success = 1;
        }
    }

    xlx_action_reply(success,data);
}

// 设备立即重启 
void xlx_action_restart(xlx_action_data *data){
    int success = 0;
    if(xlx_action_check_permission(data->t) == 1){
        success = 1;

        g_pri_restart_countdown.enable = 1;
        g_pri_restart_countdown.time = 5;


        TUTU_LOGI(TAG, "RST %s:%d", __FUNCTION__, __LINE__);

        esp_restart();

        return;
    }

    // 如果是短信又没有权限，则不回复 
    if(data->t == ACTION_TYPE_SMS && success == 0){
        data->reply = ACTION_REPLY_NO;
        return;
    }

    xlx_action_reply(success,data);
}

void xlx_action_tasklist(xlx_action_data *data){
    const size_t bytes_per_task = 40; /* see vTaskList description */
    char *task_list_buffer = malloc(uxTaskGetNumberOfTasks() * bytes_per_task);
    if (task_list_buffer == NULL) {
        TUTU_LOGE(TAG, "failed to allocate buffer for vTaskList output");
        return;
    }
    vTaskList(task_list_buffer);
    sprintf(data->outbuf,"%s %s ","Task Name\tStatus\tPrio\tHWM\tTask#\r\n", task_list_buffer);
    TUTU_LOGI(TAG, "%s", data->outbuf);  
    free(task_list_buffer);
    return;
}

// 设备立即关机 硬关机
void xlx_action_hardpoweroff(xlx_action_data *data){
    int success = 0;
    if(xlx_action_check_permission(data->t) == 1){
        success = 1;

        g_pri_power_countdown.time = 5;
        g_pri_power_countdown.enable = 1;
        TUTU_LOGI(TAG, "Power off  %s:%d", __FUNCTION__, __LINE__);
    }

    // 如果是短信又没有权限，则不回复 
    if(data->t == ACTION_TYPE_SMS && success == 0){
        data->reply = ACTION_REPLY_NO;
        return;
    }

    xlx_action_reply(success,data);
}


// 恢复出厂设置 
void xlx_action_reset(xlx_action_data *data){
    int success = 0;

    if(xlx_action_check_permission(data->t) == 1){
        // 重置配置 
        tutuconfig_load_default();        
        // 把配置入库 
        tutuconfig_save();

        // 删除APN文件配置
        // g_tutufile.my_delfile("apn.txt");
        
        // 5s后重启设备 
        g_tutuparam.restart_cfg.enable = 1;
        g_tutuparam.restart_cfg.time = 5;

        success = 1;
    }

    // 如果是短信又没有权限，则不回复 
    if(data->t == ACTION_TYPE_SMS && success == 0){
        data->reply = ACTION_REPLY_NO;
        return;
    }

    xlx_action_reply(success,data);
}

// 设置连接服务器的ip和端口 
// 先登录 AT+XLX=login,123456,30
// AT+XLX=SetServer,device.xiaolangxing.com,2379        测试环境
void xlx_action_setserver(xlx_action_data *data){
    int success = 0;
    if(data->argc >= 3){
        if(xlx_action_check_permission(data->t) == 1){
            memset(g_tutuservercfg.server_host,0,64);
            xlx_strcopy(g_tutuservercfg.server_host,63,data->argv[1]);
            g_tutuservercfg.server_port = atoi(data->argv[2]);
            tutuconfig_save_servercfg();

            success = 1;
            // 5s后重启设备 
            g_tutuparam.restart_cfg.enable = 1;
            g_tutuparam.restart_cfg.time = 5;
        }
        xlx_action_reply(success,data);
    }
    else if(data->argc == 1){
        // 显示当前服务器参数
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"server= %s:%d",
            g_tutuservercfg.server_host,
            g_tutuservercfg.server_port
        );        
    }
    else {
        xlx_action_reply(success,data);
    }    
}


// 设备立即关机,保留心跳，关闭定位和其他所有功能 
void xlx_action_poweroff(xlx_action_data *data){
    int success = 0;

    if(xlx_action_check_permission(data->t) == 1){

        if(data->argc >= 2 && strcasecmp("yes",data->argv[1]) == 0){
            // 真关机，则切换到短信模式 

        }else{
            // tutumode_switch(TUTU_WORK_MODE_SMS_AND_TRACK);// 假关机，则切换成心跳模式 
        }
        success = 1;
    }

    xlx_action_reply(success,data);

    if(data->t == ACTION_TYPE_WEB){
        // 发送设备状态同步到服务器 
        tutuapi_send_device_status_msg();
    }
}

// 设备立即开机，开启定位 
void xlx_action_poweron(xlx_action_data *data){
    int success = 1;

    // tutumode_switch(TUTU_WORK_MODE_NORMAL);

    xlx_action_reply(success,data);
}

// 声控告警状态设置（持续声控告警，智能声控告警，开启，关闭) 
void xlx_action_recordaudio(xlx_action_data *data){
    if(xlx_action_check_permission(data->t) == 1){
        *(data->outbuf) = '\0';
        if(data->argc >= 2){
            g_tutuconfig.audio_mode.hold_time = g_tutuconfig.audio_mode.hold_time_final = 0;
            if(strcasecmp("close",data->argv[1]) == 0){
                // 关闭声控告警 
                g_tutuconfig.audio_mode.mode = 0;

                sprintf(data->outbuf,"RecordAudio close,ok\n");
            }else if(strcasecmp("open",data->argv[1]) == 0){
                // 开启声控告警 
                g_tutuconfig.audio_mode.mode = 1;

                sprintf(data->outbuf,"RecordAudio open,ok\n");
            }else if(strcasecmp("smart",data->argv[1]) == 0){
                // 智能声控告警 
                g_tutuconfig.audio_mode.mode = 3;

                sprintf(data->outbuf,"RecordAudio smart,ok\n");
            }else if(strcasecmp("hold",data->argv[1]) == 0){
                // 持续声控告警 
                int hold_time = 30;// 默认30秒 
                if(data->argc > 2){
                    hold_time = atoi(data->argv[2]);
                }

                // 记录收到指令的时间 
                // TUTU_LOGI(TAG, "GET_UTC_timestamp %s:%d", __FUNCTION__, __LINE__);
                g_tutuconfig.audio_mode.cmd_time = g_tutuos.get_utc_timestamp();

                if(hold_time <= 0){
                    g_tutuconfig.audio_mode.mode = 1;
                }else{
                    g_tutuconfig.audio_mode.mode = 2;
                    g_tutuconfig.audio_mode.hold_time = g_tutuconfig.audio_mode.hold_time_final = hold_time;
                }

                sprintf(data->outbuf,"RecordAudio hold,ok\n");
            }else{
                sprintf(data->outbuf,"RecordAudio %s,failt\n",data->argv[1]);
            }
            
            tutu_save_config_flag = 1;
        }

        if(strlen(data->outbuf) < 1){
            xlx_action_reply(0,data);
        }

        if(data->t == ACTION_TYPE_WEB){
            // 发送设备状态同步到服务器 
            tutuapi_send_device_status_msg();
        }
        return;
    }
    
    data->reply = ACTION_REPLY_NO;
}


// 设置震动灵敏度 
void xlx_action_setshake(xlx_action_data *data){
    int success = 0;

    if(data->argc > 1){
        success = 1;
        g_tutuconfig.shake_sensitivity = atoi(data->argv[1]);
        tutu_save_config_flag = 1;
    }

    xlx_action_reply(success,data);
    
}

// 设置声控告警灵敏度,声控告警持续时间 
void xlx_action_setaudiodbmh(xlx_action_data *data){
    int success = 0;

    if(data->argc > 1){
        success = 1;
        g_tutuconfig.audio_sensitivity_hold_time = atoi(data->argv[1]);
        tutu_save_config_flag = 1;
    }

    xlx_action_reply(success,data);
}

// 设置声控告警灵敏度 
void xlx_action_setaudiodbm(xlx_action_data *data){
    int success = 0;

    if(data->argc > 1){
        success = 1;
        g_tutuconfig.audio_sensitivity = atoi(data->argv[1]);
        tutu_save_config_flag = 1;
    }

    xlx_action_reply(success,data);
}

// 获取声控告警灵敏度和持续时间 
void xlx_action_getaudiodbm(xlx_action_data *data){
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"GetAudioDbmInfo value=%d hold_time=%d\n",
        g_tutuconfig.audio_sensitivity,
        g_tutuconfig.audio_sensitivity_hold_time
    );
}

// 设置sos号码 
void xlx_action_setsos(xlx_action_data *data){
    int i = 0;
    int success = 0;

    if(xlx_action_check_permission(data->t) == 1){
        for(i = 0;i < 5;i++){
            memset(g_tutuconfig.sos_phonenum[i],0,15);
        }

        if(strcmp(data->argv[1],"0") == 0){
            // 关闭 
        }else{
            for(i = 1;i < data->argc;i++){
                if(0 < strlen(data->argv[i]) && (i-1) < 5){
                    xlx_strcopy(g_tutuconfig.sos_phonenum[i - 1],15,data->argv[i]);
                }
            }
        }

        tutu_save_config_flag = 1;
        success = 1;
    }

    xlx_action_reply(success,data);
}

/*
* 设置号码接听白名单 
* AT+XLX=Login,123456,30
* AT+XLX=SetWhite,1,num1,num2..num5
*/
void xlx_action_setwhite(xlx_action_data *data){
    int i = 0;
    int success = 0;

    if(xlx_action_check_permission(data->t) == 1){
        for(i = 0;i < 5;i++){
            memset(g_tutuconfig.white_phonenum[i],0,15);
        }

        if(strcmp(data->argv[1],"0") == 0){
            // 取消，所有人都可以打进来 
        }else{
            i = 1;
            if(strcmp(data->argv[1],"1") == 0){
                i++;
            }
            for(;i < data->argc;i++){
                if(0 < strlen(data->argv[i]) && (i-1) < 5){
                    xlx_strcopy(g_tutuconfig.white_phonenum[i - 1],15,data->argv[i]);
                }
            }
        }
        
        tutu_save_config_flag = 1;
        success = 1;
    }

    xlx_action_reply(success,data);
}

/* 设置定位数据上报时间间隔（秒） 
* AT+XLX=SetGpsCfg,80
*/
void xlx_action_setgpscfg(xlx_action_data *data){
    int success = 0;

    if(data->argc > 1){        
        int time = 0;
        time = atoi(data->argv[1]);
        if(time > 0){
            // 设置gps上传间隔时间 
            g_tutuconfig.gps_inteval = time;
            tutu_save_config_flag = 1;
        }
        success = 1;
    } 
    else if(data->argc == 1){
        sprintf(data->outbuf, "gpsInteval=%ld",g_tutuconfig.gps_inteval);
        return;
    }

    xlx_action_reply(success,data);
}

//设置心跳上报时间间隔（秒）
void xlx_action_setHeartbeat(xlx_action_data *data){
    int success = 0;

    if(data->argc > 1){
        
        int time = 0;
        time = atoi(data->argv[1]);
        if(time > 0){
            //设置gps上传间隔时间
            g_tutuconfig.snd_heart_time = time;
            tutu_save_config_flag = 1;
        }
        success = 1;
        xlx_action_reply(success,data);        
    }
    else  if(data->argc == 1){      // 查看目前参数
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Heartbeat =%d\n",
            g_tutuconfig.snd_heart_time
        );
    }
}

// 计算现在到下次唤醒的时间间隔
// 格式：AT+XLX=GetNextWakeup
void xlx_action_GetNextWakeup(xlx_action_data *data){

}


// 查看唤醒源列表
// 格式：AT+XLX=GetWakeupSrc,x
// 查看 AT+XLX=GetWakeupSrc
// 清除 AT+XLX=GetWakeupSrc,0
// 增加 AT+XLX=GetWakeupSrc,1
// 手动选择最后多少条记录 AT+XLX=GetWakeupSrc,0, 6    (从最后一条开始，返回6条数据)
void xlx_action_GetWakeupSrc(xlx_action_data *data){
    int success = 1;
    int param1, param2;
    if(data->argc == 1){
        show_all_wakeup_src(0,30);    // 默认打印前面30个记录
        TUTU_LOGI(TAG, "ACTION_TYPE=%d", data->t);
        if(data->t != ACTION_TYPE_AT){
            get_all_wakeup_src_data(0,20,data->outbuf);
            return;
        }
    }
    else if(data->argc == 2){
        switch (atoi(data->argv[1]))
        {
        case 25327:        // clear
            // 清除所有记录
            clear_all_wakeup_data();
            sprintf(data->outbuf, "All wake up src data cleaned.");
            break;
        case 233:         // add
            if(data->t == ACTION_TYPE_AT)
            {
                // TUTU_LOGI(TAG, "GET_UTC_timestamp %s:%d", __FUNCTION__, __LINE__);
                g_curret_wakeup_src.datetime = g_tutuos.get_utc_timestamp(); 
                wakup_src_add(&g_sys_wakeup_src,&g_curret_wakeup_src);
                tutu_save_wakeup_src_cfg();
            }
            break;    
        case 1:         //     
            sprintf(data->outbuf, "total=%d, valid_count=%d, last_id=%d", 
                g_sys_wakeup_src.total, g_sys_wakeup_src.last_count, g_sys_wakeup_src.last_id);
            break;                 
        case 255:     // all
            // 按顺序显示所有
            show_queue_wakeup_src();
            break;              
        default:
            break;
        }
    }
    else if(data->argc == 3){    
        param1 = atoi(data->argv[1]);
        param2 = atoi(data->argv[2]);
        if(param2){
            show_all_wakeup_src(param1,param2);    // 打印从param1开始前面n个记录
            if(data->t != ACTION_TYPE_AT)   // at
            {
                get_all_wakeup_src_data(param1,param2,data->outbuf);
                return;
            }
        }
    }

    xlx_action_reply(success,data);
}

/*
RANGE 			RW 		0x0F 		40H 	YES 	默认+/- 2g
ODR_AXIS 		RW 		0x10 		0FH 	YES 	输出数据速率 Output datarate
MODE_BW 		RW 		0x11 		9EH 	YES 	休眠/带宽
SWAP_POLARITY 	RW 		0x12 		0EH 	YES 	交换极性
INT_SET1 		RW 		0x16 		00H 	YES 	哪些轴产生中断
INT_SET2 		RW 		0x17 		00H 	YES 	新数据中断
INT_MAP1 		RW 		0x19 		00H 	YES 	轴中断时输出到INT脚
INT_MAP2 		RW 		0x1A 		00H 	YES 	新数据中断输出到INT脚
INT_CONFIG 		RW 		0x20 		01H 	YES 	INT脚配置/清除INT/INT中断电平
INT_LATCH 		RW 		0x21 		00H 	YES 	INT脚电平保持时间
ACTIVE_DUR 		RW 		0x27 		00H 	YES 	唤醒时长
ACTIVE_THS 		RW 		0x28 		14H 	YES		唤醒阈值
*/

/*
* 读sensor寄存器数据
AT+XLX=ReadSensorReg,1
*/
void xlx_action_ReadSensorReg(xlx_action_data *data){
#if 0    
    unsigned char reg_id, reg_value;

    // 读取数据
    if(data->argc == 2){
        reg_id =  atoi(data->argv[1]);
        if((reg_id >= 0) && (reg_id <= 0xFF)){
            reg_value = g_tutusensor.read_reg(reg_id);
            snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Read: Da218B REG_0x%02X=0x%02X",reg_id, reg_value);
        }
        else {
            snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Da218B REG %s invalid !!!",data->argv[1]);
        }
    }
    else 
#endif    
    {
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Read Da218B REG %s failed !!!",data->argv[1]);
    }
}

/*
* 写sensor寄存器
AT+XLX=WriteSensorReg,40,20 
*/
void xlx_action_WriteSensorReg(xlx_action_data *data){
#if 0    
    unsigned char reg_id, reg_value;

    // 读取数据
    if(data->argc == 3){
        reg_id =  atoi(data->argv[1]);
        reg_value =  atoi(data->argv[2]);
        if((reg_id >= 0) && (reg_value >= 0) && (reg_id <= 0xFF) && (reg_value <= 0xFF)){
            g_tutusensor.write_reg(reg_id,reg_value);
            snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Write Da218B REG_0x%02X=0x%02X OK!",reg_id, reg_value);
        }
        else {
            snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Da218B REG (%s=%s) invalid !!!",data->argv[1],data->argv[2]);
        }
    }
    else 
#endif
    {
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Read Da218B REG (%s=%s) failed !!!",data->argv[1],data->argv[2]);
    }
}

/*
* 语音呼叫其他号码
* 拨打电话
AT+XLX=Callout,10086
*/
void xlx_action_Callout(xlx_action_data *data){
    uint16_t success = 0;
#if 0    
    char call_num[64]= {0};
    if(data->argc == 2){        
        // 呼叫结束        
        sprintf(call_num, "ATD%s;\r\n", data->argv[1]);
        TUTU_LOGI(TAG, "call: %s", call_num);
        success = hal_modem_atcmd_exe(call_num, "OK", 2000);   
    }
#endif    
    xlx_action_reply(success,data);
}

/*
* 语音呼叫其他号码
* 拨打电话
AT+XLX=Callout,10086
*/
void xlx_action_Callend(xlx_action_data *data){
    uint16_t success = 0;
#if 0    
    if(data->argc == 2){
        // 呼叫结束
        success = hal_modem_atcmd_exe("ATH", "OK", 2000);   
    }
#endif    
    xlx_action_reply(success,data);
}

/*
* 发送短消息
AT+XLX=PlayTTS,123
*/
void xlx_action_PlayTTS(xlx_action_data *data){
    uint16_t success = 0;
#if 0    
    if(data->argc == 2){
        g_tutuos.play_tts(data->argv[1],0,0); //播放TTS语音
    }
#endif    
    xlx_action_reply(success,data);
}

/*
* 停止播放TTS
AT+XLX=StopTTS
*/
void xlx_action_StopTTS(xlx_action_data *data){
    uint16_t success = 0;
#if 0    
    if(data->argc == 1){
        if (0 == cm_local_tts_play_stop())           // 停止TTS语音
        {
            TUTU_LOGI(TAG, "tts_play_stop() success\n");
            success = 1;
        }
        else
        {
            TUTU_LOGI(TAG, "tts_play_stop() fail\n");
        }
    }
#endif    
    xlx_action_reply(success,data);
}


/*
* 发送短消息
AT+XLX=SendSMS,13798350001,hello
*/
void xlx_action_SendSMS(xlx_action_data *data){
    uint16_t success = 0;
#if 0    
    if(data->argc == 3){
        
        hal_sms_senddata((char *)data->argv[1],data->argv[2], strlen(data->argv[2])); 
        success = 1;
    }
#endif    
    xlx_action_reply(success,data);
}


#if 0
/*************************************************************************************************************************/
// 测试wifi扫描
#define STR_LEN(s) (sizeof(s) - 1)
#define STR_ITEM(s) (s), STR_LEN(s)

#include "cm_os.h"
#include "cm_wifiscan.h"

/**
 *  \brief 串口接收数据结构体
 */
typedef struct 
{
    unsigned char buf[1024];
    int len;
}cm_uart_recv_data_buf_t;
/**命令结构体*/
typedef struct cm_cmd {
    char * cmdstr;
    void (* cmdfunc)(unsigned char **,int);
} cm_cmd_t;

/**
 *  \brief 串口接收命令接口
 */
typedef struct 
{
    int cmd_execute;  //命令执行标志，1未被执行，0执行完成
    unsigned char * buf[20]; //最多接受20个参数
    int len;
}cm_uart_cmd_recv_t;
static void __NumToHex(char *inData, int inLen, char *outData)
{
    int i=0;
    char tmpBuf[10];

    memset(tmpBuf, 0, sizeof(tmpBuf));

    if (inLen > 0)
    {
        for (i = 0; i < inLen; i++)
        {
            sprintf(tmpBuf, "%02X", inData[i]);
            strcat(outData, tmpBuf);
        }
    }
}

static void __wifiscan_callback_demo(cm_wifi_scan_info_t *param, void *user_param)
{
    TUTU_LOGI(TAG, "__wifiscan_callback_demo %s\n", user_param);
    char macBuf[50];
    
    for (int i = 0; i < param->bssid_number; i++)
    {
        memset(macBuf, 0, sizeof(macBuf));
        __NumToHex((char*)param->channel_cell_list[i].bssid, sizeof(param->channel_cell_list[i].bssid), macBuf);
        TUTU_LOGI(TAG, "%d, %s, %d, %d\n", i+1, macBuf, param->channel_cell_list[i].rssi, param->channel_cell_list[i].channel_number);
    }
}
#endif

/* 
 * 执行测试命令 
 * AT+XLX=TestWifiscan,CFG
 * AT+XLX=TestWifiscan,START
 * AT+XLX=TestWifiscan,STOP
 * AT+XLX=TestWifiscan,QUERY
*/
void xlx_action_TestWifiscan(xlx_action_data *data)
{
    int success = 1;
#if 0    
    unsigned char operation[20] = {0};
    sprintf((char *)operation, "%s", data->argv[1]);

    /* CM:WIFISCAN:CFG */
    /* 测试需首先进行参数配置 */
    if (0 == strcmp((const char *)operation, "CFG")) //开始录音，需配合结束录音指令使用，CM:AUDIO_RECORD:PCMSTART 
    {
        uint8_t round = 3;
        uint8_t max = 6;
        uint8_t time_out = 15;
        uint8_t priority = CM_WIFI_SCAN_WIFI_HIGH;

        if (cm_wifiscan_cfg(CM_WIFI_SCAN_CFG_ROUND, &round))
        {
            TUTU_LOGI(TAG, "wifiscan cfg round err\n");
        }

        if (cm_wifiscan_cfg(CM_WIFI_SCAN_CFG_MAX_COUNT, &max))
        {
            TUTU_LOGI(TAG, "wifiscan cfg max err\n");
        }

        if (cm_wifiscan_cfg(CM_WIFI_SCAN_CFG_TIMEOUT, &time_out))
        {
            TUTU_LOGI(TAG, "wifiscan cfg time_out err\n");
        }
        
        if (cm_wifiscan_cfg(CM_WIFI_SCAN_CFG_PRIORITY, &priority))
        {
            TUTU_LOGI(TAG, "wifiscan cfg priority err\n");
        }
    }
    
    /* CM:WIFISCAN:START */
    /* 开始扫描，扫描结果将从回调函数异步上报，切换CFUN过程中禁止扫描WiFi */
    else if (0 == strcmp((const char *)operation, "START"))
    {
        if(cm_wifiscan_start((cm_wifiscan_callback_t)__wifiscan_callback_demo, "wifiscan"))
        {
            TUTU_LOGI(TAG, "wifiscan start err\n");
        }
    }

    /* CM:WIFISCAN:STOP */
    /* 停止扫描，超时时间未到或结果未完全返回时，可中断wifiscan功能 */
    else if (0 == strcmp((const char *)operation, "STOP"))

    {
        if(cm_wifiscan_stop())
        {
            TUTU_LOGI(TAG, "wifiscan stop err\n");
        }
    }

    /* CM:WIFISCAN:QUERY */
    /* 查询扫描结果，查询返回的是最后一次扫描的结果 */
    else if (0 == strcmp((const char *)operation, "QUERY"))
    {
        cm_wifi_scan_info_t *param = NULL;
        if(cm_wifiscan_query(&param))
        {
            TUTU_LOGI(TAG, "wifiscan query err\n");
        }

        char macBuf[50];

        for(int i = 0; i < param->bssid_number; i++)
        {
            memset(macBuf,0,sizeof(macBuf));
            __NumToHex((char*)param->channel_cell_list[i].bssid, sizeof(param->channel_cell_list[i].bssid), macBuf);
            TUTU_LOGI(TAG, "%d, %s, %d, %d\n", i+1, macBuf, param->channel_cell_list[i].rssi, param->channel_cell_list[i].channel_number);
        }
    }
    else {
        success = 0;
    }
#endif

    xlx_action_reply(success,data);

}
// wifi scan  end
/*************************************************************************************************************************/

/*
* 整点报时时段设置
  格式：AT+XLX=HourRemind,hh:mm-hh:mm
  样例：AT+XLX=HourRemind,08:00-20:00
  查询：AT+XLX=HourRemind
*/
void xlx_action_HourRemind(xlx_action_data *data){
    uint16_t success = 0;
    char * p_data = NULL;
    char param[6];
    uint8_t start_time, end_time;
    uint16_t pos;
    if(data->argc == 1){
        
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"HourRemind:%d:00-%d:59\n",
            g_tutuconfig.tell_time_start, g_tutuconfig.tell_time_end);
        return;
    }
    else if(data->argc == 2){
        pos = search_sub_str_position("-",data->argv[1]);
        if((pos>0) && (pos<6)){            
            p_data = data->argv[1]+pos;  // 后半部分

            memset(param,0,sizeof(param));
            strncpy(param,data->argv[1],pos-1);

            // 查冒号
            pos = search_sub_str_position(":",param);
            if(pos == 0){
                start_time = atoi(param);
            }
            else{
                // 08:00
                param[pos-1] = 0x00;
                start_time = atoi(param); 
            }
            
            // 后半部分
            memset(param,0,sizeof(param));
            strcpy(param,p_data);
            // 查冒号
            pos = search_sub_str_position(":",param);
            if(pos == 0){
                end_time = atoi(param);
            }
            else{
                // 18:00
                param[pos-1] = 0x00;
                end_time = atoi(param); 
            }

            if((start_time < 24) && (end_time < 24)){
                g_tutuconfig.tell_time_start = start_time;
                g_tutuconfig.tell_time_end = end_time;
                tutu_save_config_flag = 1;
                success = 1;
            }
        }
    }
    xlx_action_reply(success,data);
}

/*
* 
  自动飞行模式时段设置
  格式：AT+XLX=AutoFly,hh:mm,runTime,exitTime
  样例：AT+XLX=AutoFly,08:00,21600,1800
  查询：AT+XLX=AutoFly
    hh          自动进入低功耗的开始时间， 小时
    mm          自动进入低功耗的开始时间， 分钟
    runTime 进入飞行模式后多长时间退出来，单位是：秒
    exitTime 当按sos键后，上报了SOS告警后，多长时间重新进入休眠模式，单位是：秒
*/
void xlx_action_AutoFlay(xlx_action_data *data){
    uint16_t success = 0;
    char * p_data = NULL;
    char param[6];
    uint8_t start_time, end_time;
    uint16_t pos;
    if(data->argc == 1){        
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"AutoFly:%d:%d,%ld,%d\n",
            g_tutuconfig.auto_fly_time_start_hour, 
            g_tutuconfig.auto_fly_time_start_minute,
            g_tutuconfig.auto_fly_run_time,
            g_tutuconfig.auto_fly_exit_sos_time
        );
        return;
    }
    else if(data->argc == 4){
        //　开始进入的时间

        p_data = data->argv[1];  //

        memset(param,0,sizeof(param));
        strncpy(param,data->argv[1],5);
        // 查冒号
        pos = search_sub_str_position(":",param);
        
        if(pos == 0){
            success = 0;
        }
        else{
            // 08:00
            param[pos-1] = 0x00;
            start_time = atoi(param); 

            end_time = atoi(&param[pos]);

            if((start_time < 24) && (end_time < 60)){
                g_tutuconfig.auto_fly_time_start_hour = start_time;
                g_tutuconfig.auto_fly_time_start_minute = end_time;
                tutu_save_config_flag = 1;
                success = 1;
            }            

            g_tutuconfig.auto_fly_run_time = atoi(data->argv[2]);
            g_tutuconfig.auto_fly_exit_sos_time = atoi(data->argv[3]);
        }      
    }
    xlx_action_reply(success,data);
}

/*
* 音量设置
  格式：AT+XLX=VolumeControl,percent    (0~100)
  样例：AT+XLX=VolumeControl,69
  查询：AT+XLX=VolumeControl
*/
void xlx_action_VolumeControl(xlx_action_data *data){
    uint16_t success = 0;    
    if(data->argc == 1){        
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Volume:%d\n",
            g_tutuconfig.voice_volume);
        return;
    }
    else if(data->argc == 2){
        g_tutuconfig.voice_volume = atoi(data->argv[1]);
        // cm_audio_play_set_cfg(CM_AUDIO_PLAY_CFG_VOLUME, &g_tutuconfig.voice_volume); 
        tutu_save_config_flag = 1;
        success = 1;
    }
    xlx_action_reply(success,data);
}
/*
* 是否可以休眠
  格式：AT+XLX=SetSysPmWork,x       x=0不休眠，1休眠
  样例：AT+XLX=SetSysPmWork,1 
*/
void xlx_action_SetSysPmWork(xlx_action_data *data){
    uint16_t success = 0;   
#if 0    
    uint8_t mode; 
    if(data->argc == 2){
        mode = atoi(data->argv[1]);
        if(mode == 0)
        {
            cm_pm_work_lock();
            osDelay(2);
            TUTU_LOGI(TAG, "cm_pm_work_lock");
        }
        else
        {
            // 关闭所有LED
            g_tutuled.close_led(LED_GPS);
            g_tutuled.close_led(LED_POWER);
            g_tutuled.close_led(LED_4G); 

            // 关闭GPS
            g_tutuuartgps.disable_power();
            tutu_gpio_set_level(SPEAKER_ENABLE_GPIO, 0);		// 关闭功放
                     
            TUTU_LOGI(TAG, "cm_pm_work_unlock");
            osDelay(2);            
            cm_pm_work_unlock();
        }

        success = 1;
    }
#endif
    xlx_action_reply(success,data);
}

/*
* 设查询时间
  格式：AT+XLX=SetSpeaker, x
  样例：AT+XLX=SetSpeaker,1 打开免提功放 
*/
void xlx_action_SetSpeaker(xlx_action_data *data){
    uint16_t success = 0;   
#if 0    
    uint8_t io_level; 
    if(data->argc == 2){
        io_level = atoi(data->argv[1]);
        cm_gpio_set_level(SPEAKER_ENABLE_GPIO, io_level);
        success = 1;
    }
#endif
    xlx_action_reply(success,data);        
}

/*
* 设置和查询时间
  格式：AT+XLX=RtmpParams, format,rate,channels     带3个参数

样例：AT+XLX=RtmpParams,1           带一个参数：打开播放，停止播放
  样例：AT+XLX=RtmpParams   查询        不带参数

  样机：AT+XLX=RtmpParams,2,7,2         (16位深度，44k采样，双通道) 
*/
void xlx_action_RtmpParams(xlx_action_data *data){
    uint16_t success = 0;   
#if 0    
    uint8_t io_level; 
    if(data->argc == 1){
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"rtmp_play: %d,%d,%ld,%d",
            g_tutuconfig.rtmp_play_format,          // 1=pcm, 3=mp3
            g_tutuconfig.rtmp_play_sample_fmt,      // 1=8bits, 2=16bits
            g_tutuconfig.rtmp_play_sample_rate,    // 0=8, 7=44k
            g_tutuconfig.rtmp_play_channel         // 单通道    
            );     
        success = 1;
        return;
    }
    else if(data->argc == 2){
        if(1==atoi(data->argv[1])){
            cm_audio_sample_param_t frame = {
                .sample_format = g_tutuconfig.rtmp_play_sample_fmt,
                .rate = g_tutuconfig.rtmp_play_sample_rate, 
                .num_channels = g_tutuconfig.rtmp_play_channel};
            TUTU_LOGI(TAG, "pull_stream player_stream_open: %d\n", 
                cm_audio_player_stream_open(g_tutuconfig.rtmp_play_format, &frame));    
        }
        else{
            cm_audio_player_stream_close();
        }
        success = 1;
    }    
    else if(data->argc == 5){
            g_tutuconfig.rtmp_play_format = atoi(data->argv[1]);         // 1=pcm, 3=mp3
            g_tutuconfig.rtmp_play_sample_fmt = atoi(data->argv[2]);      // 1=8bits, 2=16bits
            g_tutuconfig.rtmp_play_sample_rate = atoi(data->argv[3]);    // 0=8, 7=44k
            g_tutuconfig.rtmp_play_channel = atoi(data->argv[4]);         // 单通道         
        tutu_save_config_flag = 1;
        success = 1;
    }
#endif    
    xlx_action_reply(success,data);        
}


/*
* 设置查询 RTMP 拉流时 日志是否打印包信息
  格式：AT+XLX=ShowPullPackLog
  样例：AT+XLX=ShowPullPackLog,1
*/
void xlx_action_showpullpacklog(xlx_action_data *data){
    uint16_t success = 0;    
#if 0    
    if(data->argc == 1){        
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"show_pull_pack_log:%d\n",
            get_show_pull_pack_log());
        return;
    }
    else if(data->argc == 2){
        set_show_pull_pack_log(atoi(data->argv[1]));
        success = 1;
    }
#endif    
    xlx_action_reply(success,data);
}

/*
* 设置查询 RTMP 拉流时 日志是否打印包信息
  格式：AT+XLX=SetPullRtmpBuffSize
  样例：AT+XLX=SetPullRtmpBuffSize,640
*/
void xlx_action_SetPullRtmpBuffSize(xlx_action_data *data){
    uint16_t success = 0;    
#if 0    
    if(data->argc == 1){        
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"PullRtmpBuffSize:%d\n",
            get_pull_rtmp_buff_size());
        return;
    }
    else if(data->argc == 2){
        set_pull_rtmp_buff_size(atoi(data->argv[1]));
        success = 1;
    }
#endif    
    xlx_action_reply(success,data);
}

/*
* 模拟按键，参数SOS呼叫
  格式：AT+XLX=SetSosCall
  样例：AT+XLX=SetSosCall
*/
void xlx_action_SetSosCall(xlx_action_data *data){
    // g_tututel.tel_set_sos_status(1);    // 开启紧急呼叫
    xlx_action_reply(1,data);
}

/*
* 模拟按键，参数SOS呼叫
  格式：AT+XLX=SetSosThread,x,y x=0，表示所有
  样例：AT+XLX=SetSosThread,0,1
*/
// extern int set_sos_key_scan_thread_state(uint8_t option);
void xlx_action_SetSosThreadState(xlx_action_data *data){
    uint16_t success = 0;    
#if 0    
    uint16_t fun_id;
    uint16_t option_id;
    if(data->argc == 3){        
        fun_id = atoi(data->argv[1]);
        option_id = atoi(data->argv[2]);

        set_all_sleep_thread_state(fun_id, option_id);
        success = 1;
    }
#endif
    xlx_action_reply(success,data);
}

/*
* 模拟按键，参数SOS呼叫
  格式：AT+XLX=SetAllEvent,x,y x=0，表示所有
  样例：AT+XLX=SetAllEvent,0,1
*/
// extern void set_all_event_state(unsigned char fun_id, uint8_t option);
void xlx_action_SetAllEvent(xlx_action_data *data){
    uint16_t success = 0;    
#if 0    
    uint16_t fun_id;
    uint16_t option_id;
    if(data->argc == 3){        
        fun_id = atoi(data->argv[1]);
        option_id = atoi(data->argv[2]);

        set_all_event_state(fun_id, option_id);
        success = 1;
    }
#endif
    xlx_action_reply(success,data);
}

/*
* 读出 保存的rtmp文件，并显示
  格式：AT+XLX=Set1sTimer
  样例：AT+XLX=Set1sTimer,1
*/
void xlx_action_Set1sTimer(xlx_action_data *data){
    uint16_t success = 0;    
#if 0    
    uint16_t action_id;
    if(data->argc == 2){        
        action_id = atoi(data->argv[1]);
        set_hal_sysruntime_timer(action_id);
        success = 1;
    }
#endif
    xlx_action_reply(success,data);
}


/*
* 读出 保存的rtmp文件，并显示
  格式：AT+XLX=GpioRW,io,rw
  样例：AT+XLX=GpioRW,1,1   
*/
void xlx_action_GpioRW(xlx_action_data *data){
    uint16_t success = 0;    
#if 0    
    uint16_t io_num, io_level;
    if(data->argc == 2){     // 读出   
        io_num = atoi(data->argv[1]);
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"io_#%d_level= %d",tutu_gpio_get_level(io_num));
        return;
    }
    else {      // 写入
        io_num = atoi(data->argv[1]);
        io_level = atoi(data->argv[2]);
        if(0 == tutu_gpio_set_level(io_num, io_level)){
            success = 1;
        }
        else {
            
        }
    }
#endif
    xlx_action_reply(success,data);
}

/*
  格式：AT+XLX=PlayKeyTTS,x
  样例：AT+XLX=PlayKeyTTS,1 
*/
void xlx_action_PlayKeyTTS(xlx_action_data *data){
    int success = 0;
#if 0    
    int status = 0;
    if(data->argc > 1){
        // 开启日志 
        status = atoi(data->argv[1]);

        if(status == 1){
            tutu_play_sos_key_tts = 1;
        }else{
            tutu_play_sos_key_tts = 0;
        }
        success = 1;
    }
#endif    
    xlx_action_reply(success,data);
}

#define AT_CMD_BUFF_LEN_MAX 256
/*
* 发AT命令
* AT+XLX=ATCMD,x,y,z...
* AT+XLX=ATCMD,AT+MEDCR=0,34,2
*/
void xlx_action_atcmd(xlx_action_data *data)  
{
    int success = 0;

#if 0    
    char at_buff[AT_CMD_BUFF_LEN_MAX] = {0};
	char response[128] = {0};
    int i;

    if(data->argc > 1){
        for(i=1;i<data->argc;i++){
            strcat((char *)at_buff,(char *)data->argv[i]);
            if(i != (data->argc-1)){
                strcat((char *)at_buff, ",");
            }
        }
        strcat((char *)at_buff, "\r\n");
        TUTU_LOGI(TAG, "CMD: %s", at_buff);
        hal_modem_atcmd_exeEx(at_buff, "OK", response, 2000);
        if(response[0] != 0){
            snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Ret: %s",response);                
            return;        
        }
    }
#endif    
    xlx_action_reply(success,data);
}

/*
 * 驱动剩余内存大小
*/
void xlx_action_GetHeap(xlx_action_data *data){
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Free heap: %ld",  esp_get_free_heap_size()); 
}

/*
* 读出 保存的rtmp文件，并显示
  格式：AT+XLX=LogShowRtmpFileData
  样例：AT+XLX=LogShowRtmpFileData
*/
void xlx_action_LogShowRtmpFileData(xlx_action_data *data){
    uint16_t success = 0;    
#if 0    
    if(data->argc == 1){        
        log_show_rtmp_file_data();
    }
#endif    
    xlx_action_reply(success,data);
}

/*
* 查看和设置 GPS 多长时间打开一次 
  格式：AT+XLX=SetOpenGpsInterval
  样例：AT+XLX=SetOpenGpsInterval,1200
*/
void xlx_action_SetOpenGpsInterval(xlx_action_data *data){
    uint16_t success = 0;    
    if(data->argc == 1){        
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"OpenGpsInterval:%ld\n",
            g_tutuconfig.auto_open_gps_interval);
        return;
    }
    else if(data->argc == 2){
        g_tutuconfig.auto_open_gps_interval = atoi(data->argv[1]);
        success = 1;
    }
    xlx_action_reply(success,data);
}

/*
* 设查询时间
  格式：AT+XLX=GetTime
  样例：AT+XLX=GetTime 
*/
void xlx_action_GetTime(xlx_action_data *data){
    TutuTime t = {0};
    tutuos_get_rtc_time(&t);
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"time:%d-%d-%d %d:%d:%d",t.year,t.mon,t.day,t.hour,t.min,t.sec);    
}

/*
* 设查询时间
  格式：AT+XLX=GetStampToTime,
  样例：AT+XLX=GetTime  

    int tm_sec;   // seconds after the minute - [0, 60] including leap second
    int tm_min;   // minutes after the hour - [0, 59]
    int tm_hour;  // hours since midnight - [0, 23]
    int tm_mday;  // day of the month - [1, 31]
    int tm_mon;   // months since January - [0, 11]
    int tm_year;  // years since 1900
    int tm_wday;  // days since Sunday - [0, 6]
    int tm_yday;  // days since January 1 - [0, 365]
    int tm_isdst; // daylight savings time flag
*/
void xlx_action_GetStampToTime(xlx_action_data *data){
     if(data->argc == 2){
        time_t loc_timestamp;
        loc_timestamp = atoi(data->argv[1]); 
        loc_timestamp += 28800;
        struct tm *t = localtime(&loc_timestamp); // 转换为本地时间         
        t->tm_year += 1900;
        t->tm_mon += 1;
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"time:%d-%d-%d %d:%d:%d(week: %d)",
            t->tm_year,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec, t->tm_wday);            
     }
}

/*
* 收到同步NTPT时间
*/
void xlx_action_SyncNtpTime(xlx_action_data *data){
     if(data->argc == 1){
        // tutu_sync_ntp();     
        xlx_action_reply(1,data);  
     }
}

/*
LED 控制
  格式：AT+XLX=SetLed,id,on_off
  样例：AT+XLX=SetLed,2,1      LED_POWER 开
    id: 0~3     0表示全部，1/2/3 表示3个LED
            1   LED_GPS,
            2   LED_POWER,
            3   LED_4G,
    on_off:     1开，0关
*/
void xlx_action_SetLed(xlx_action_data *data){
#if 0    
    uint8_t led_id, led_switch;
     if(data->argc == 3){
        led_id = atoi(data->argv[1]); 
        led_switch = atoi(data->argv[2]);
        switch (led_id)
        {
        case 0:
            if(led_switch){
                g_tutuled.open_led(LED_GPS);
                g_tutuled.open_led(LED_POWER);
                g_tutuled.open_led(LED_4G);
            }
            else {
                g_tutuled.close_led(LED_GPS);
                g_tutuled.close_led(LED_POWER);
                g_tutuled.close_led(LED_4G);
            }
            break;  
        case 1:
        case 2:
        case 3:
            if(led_switch)
                g_tutuled.open_led(led_id-1);
            else
                g_tutuled.close_led(led_id-1);
            break;        
        default:        
            break;
        }    
        xlx_action_reply(1,data);      
     }
    else {
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Failed! Parameters Error!(e.g. SetLed,id,on_off)[id:0~3]");
    }     
#else
    xlx_action_reply(0,data);
#endif
}

// 开启拐点补传 
void xlx_action_setuploadturn(xlx_action_data *data){
    int success = 0;

    if(data->argc > 1){

        if(strcasecmp("open",data->argv[1]) == 0){
            success = 1;
            g_tutuconfig.enable_status |= ENABLE_TURN;
        }else if(strcasecmp("close",data->argv[1]) == 0){
            success = 1;
            if((g_tutuconfig.enable_status & ENABLE_TURN) != 0){
                g_tutuconfig.enable_status = g_tutuconfig.enable_status ^ ENABLE_TURN;
            }
        }
        tutu_save_config_flag = 1;

    }

    xlx_action_reply(success,data);
}

// 断油电控制 
void xlx_action_powerswitch(xlx_action_data *data){
    // 该版本不做实现 
}

//设置超速阀值
void xlx_action_setspeed(xlx_action_data *data){
    // 该版本不做实现 
}

// apn设置 
void xlx_action_setapn(xlx_action_data *data){
    int success = 0;

    if(data->argc >= 4){
        if(xlx_action_check_permission(data->t) == 1){
            // g_tuturil.set_apn(data->argv[1],data->argv[2],data->argv[3]);
            success = 1;
        }
    }

    xlx_action_reply(success,data);
}

// 获取gps详细信息 
void xlx_action_getgpsinfo(xlx_action_data *data){
#if 0    
    char lng[12] = {0};
    char lat[12] = {0};
    int posslnum = 0,direct = 0,gpssta = 0;
    float speed = 0;
    TutuNmeaMsg *gpsmsg = NULL;
    TutuTime t = {0};
    char nshemi = '0';
    char ewhemi = '0';


    gpsmsg = g_tutugps.get_gps_info();
    if(gpsmsg && gpsmsg->gpssta > 0){
        gpssta = gpsmsg->gpssta;
        tutu_latlng2str(gpsmsg->latitude,lat,1);
        tutu_latlng2str(gpsmsg->longitude,lng,0);
        posslnum = gpsmsg->posslnum;
        speed = gpsmsg->speed;
        direct = gpsmsg->direct/100;
        
        t.year = gpsmsg->utc.year;
        t.mon = gpsmsg->utc.month;
        t.day = gpsmsg->utc.date;
        t.hour = gpsmsg->utc.hour;
        t.min = gpsmsg->utc.min;
        t.sec = gpsmsg->utc.sec;

        ewhemi = gpsmsg->ewhemi;
        nshemi = gpsmsg->nshemi;
    }

    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"GetGpsInfo t=%d-%d-%d %d:%d:%d,lat=%s,lng=%s,satellite=%d,speed=%d,direct=%d,gpssta=%d,ew=%c,ns=%c\n",
        t.year,t.mon,t.day,t.hour,t.min,t.sec,
        lat,
        lng,
        posslnum,
        (int)speed,
        direct,
        gpssta,
        ewhemi,
        nshemi
    );
#else
    xlx_action_reply(0,data);
#endif
    if (tutu_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
}

// 设备时间相关 
void xlx_action_devicetime(xlx_action_data *data){
    uint32_t tick = g_tutuos.get_ticks();
    uint32_t t = g_tutuos.get_utc_timestamp();
    // TUTU_LOGI(TAG, "GET_UTC_timestamp %s:%d", __FUNCTION__, __LINE__);
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"DeviceTime run=%lu(s),time=%ld\n",
        tick/200,
        t
    );
}

#if 1
// 设备信息查询 
// AT+XLX=deviceinfo
void xlx_action_deviceinfo(xlx_action_data *data){  
    snprintf(data->outbuf, AT_CMD_OUT_BUFF_SIZE_MAX, "DeviceInfo %d,%s,id:%s,host=%s:%d,apn=%s;%s;%s,lat=%d,lng=%d,gps=%d,4g=%d,power=%d,mode=%d,ril=%d\n",
        get_version_code(),
        get_CHECKCODE(),
        tutu_device_imei,
        g_tutuservercfg.server_host,
        g_tutuservercfg.server_port,
        "",
        "",
        "",
        0,
        0,
        0,
        96,
        100,
        g_tutuconfig.mode,
        5
    );    
}

#else
// 设备信息查询 
// AT+XLX=deviceinfo
void xlx_action_deviceinfo(xlx_action_data *data){  
    char apnname[64]={0};
    char apnuser[64]={0};
    char apnpwd[64]={0};
    char lng[12] = {0};
    char lat[12] = {0};
    int posslnum = 0,gsm_signal = 0,power = 0;
    TutuNmeaMsg *gpsmsg = NULL;

    gpsmsg = g_tutugps.get_gps_info();
    if(gpsmsg && gpsmsg->gpssta > 0){
        tutu_latlng2str(gpsmsg->latitude,lat,1);
        tutu_latlng2str(gpsmsg->longitude,lng,0);
        posslnum = gpsmsg->posslnum;
    }
    power = g_tutubattery.get_vol_power();
    gsm_signal = (int)(g_tuturil.get_sim_signal()/31.0 * 100);


    // 通过串口发这个命令导致重启，但网页发命令不会重启
    // 去掉get_apn这个函数中的打印日志
    if(data->t == ACTION_TYPE_AT){
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"Dev: %d,%s,id:%s,host=%s:%d,lat=%s,lng=%s,gps=%d,4g=%d,power=%d,mode=%d,ril=%d\n",
            get_version_code(),                       
            get_CHECKCODE(),         
            tutu_device_imei,
            g_tutuservercfg.server_host,
            g_tutuservercfg.server_port,                       
            lat,
            lng,      
            posslnum,          
            gsm_signal,            
            power,            
            g_tutuconfig.mode,
            g_tuturil.get_sim_status()           
        );      
    }
    else {    
        g_tuturil.get_apn(apnname,apnuser,apnpwd);
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"DeviceInfo %d,%s,id:%s,host=%s:%d,apn=%s;%s;%s,lat=%s,lng=%s,gps=%d,4g=%d,power=%d,mode=%d,ril=%d\n",
            get_version_code(),
            get_CHECKCODE(),
            tutu_device_imei,
            g_tutuservercfg.server_host,
            g_tutuservercfg.server_port,
            apnname,
            apnuser,
            apnpwd,
            lat,
            lng,
            posslnum,
            gsm_signal,
            power,
            g_tutuconfig.mode,
            g_tuturil.get_sim_status()
        );  
    }
}
#endif

static int enable_names_size = 12;
// 如果此表变动，需要修改上面的size 
static char *enable_names[] = {
    "shake",
    "fencein",
    "fenceout",
    "speed",
    "power",
    "sos",
    "uninstall",
    "net",
    "gps",
    "turn",
    "acc",
    "air",
    0
};
 
/*
* 开启设备指定功能 
* AT+XLX=login,123456,30
* AT+XLX=Open,gps,shake
* 一次可以开启多个
* 关闭使用Close指令
*/
void xlx_action_open(xlx_action_data *data){
    int success = 0;

    if(data->argc >= 2){

        if(xlx_action_check_permission(data->t) == 1){
            
            int enable = 0;
            int i = 0,j = 0;
            
            for(i = 1;i < data->argc;i++){
                for(j = 0;j < enable_names_size;j++){
                    if(strcasecmp(data->argv[i],enable_names[j]) == 0){
                        enable |= (1 << j);
                        break;
                    }
                }
            }

            g_tutuconfig.enable_status |= enable;
            
            if (g_tutuconfig.enable_status & ENABLE_SHAKE) {    //震动开启单独的上报开关
                g_tutuconfig.shake_alert_enable = 1;     //开启
            }

            success = 1;
            tutu_save_config_flag = 1;
        }

        
    }

    xlx_action_reply(success,data);
    
}

/*
* 关闭设备指定功能 
* AT+XLX=login,123456,30
* AT+XLX=Open,gps,shake
* 一次可以开启多个
* 关闭使用Close指令
*/
void xlx_action_close(xlx_action_data *data){
    int success = 0;

    if(data->argc >= 2){
        
        if(xlx_action_check_permission(data->t) == 1){
            
            int mask = 0;
            int i = 0,j = 0;
            
            for(i = 1;i < data->argc;i++){
                for(j = 0;j < enable_names_size;j++){
                    if(strcasecmp(data->argv[i],enable_names[j]) == 0){
                        mask = (1 << j);
                        if((g_tutuconfig.enable_status & mask) != 0){
                            g_tutuconfig.enable_status=g_tutuconfig.enable_status ^ mask;
                        }
                        break;
                    }
                }
            }

            if (!(g_tutuconfig.enable_status & ENABLE_SHAKE)) {    //震动关闭单独的上报开关
                g_tutuconfig.shake_alert_enable = 0;     //关闭
            }

            success = 1;
            tutu_save_config_flag = 1;
        }

    }

    xlx_action_reply(success,data);
    
}

// 获取设备已经开启的所有功能 
void xlx_action_openlist(xlx_action_data *data){
    int i = 0;
    char buf[128] = {0};// 如果enable_names增加，需要计算缓冲区是否要加大 
    int offset = 0;
    uint32_t enable = g_tutuconfig.enable_status;
    
    sprintf(buf,"OpenList ");
    offset = 9;

    for(i = 0;i < enable_names_size;i++){// enable_names长度当前为11 
        if((enable & 1) != 0){
            if (i == 0) {   //shake
                sprintf(buf + offset,"%s%d,",enable_names[i], g_tutuconfig.shake_alert_enable);
                offset += strlen(enable_names[i]) + 2;
            } else {
                sprintf(buf + offset,"%s,",enable_names[i]);
                offset += strlen(enable_names[i]) + 1;
            }
        }

        enable = enable >> 1;
        
        if(enable == 0){
            break;
        }
    }

    if(offset > 9){
        buf[offset - 1] = '\n';
    }else{
        buf[offset] = '\n';
    }

    
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"%s",buf);

}

// 获取设备已经关闭的所有功能
void xlx_action_closelist(xlx_action_data *data){
    int i = 0;
    char buf[128] = {0};// 如果enable_names增加，需要计算缓冲区是否要加大 
    int offset = 0;
    uint32_t enable = g_tutuconfig.enable_status;
    
    sprintf(buf,"CloseList ");
    offset = 10;

    for(i = 0;i < enable_names_size;i++){// enable_names长度当前为11 
        if((enable & 1) == 0){
            sprintf(buf + offset,"%s,",enable_names[i]);
            offset += strlen(enable_names[i]) + 1;
        } else if (i == 0 && !g_tutuconfig.shake_alert_enable) {    //shake，开启，关闭状态
            sprintf(buf + offset,"%s%d,",enable_names[i], g_tutuconfig.shake_alert_enable);
            offset += strlen(enable_names[i]) + 2;
        }

        enable = enable >> 1;
        
        if(enable == 0){
            break;
        }
    }

    if(offset > 10){
        buf[offset - 1] = '\n';
    }else{
        buf[offset] = '\n';
    }

    sprintf(data->outbuf,"%s",buf);
}

// 获取位置 
void xlx_action_getgps(xlx_action_data *data){
    int success = 1;

    if(g_tutuparam.shake_state == 0){
        g_tutuparam.flag_enter_heart_code = 1;
    }else{
        // 允许进入立即定位代码一次 
        g_tutuparam.flag_enter_gps_pos_code = 2;
    }

    xlx_action_reply(success,data);
}

/* 马上采集一次位置信息 */
void xlx_action_nowgps(xlx_action_data *data){
    int success = 1;
    
    // 老人机1个小时定位一次，所有收到2个有效点后，关闭了gps
    if(!g_tutuparam.enable_gps_unit){
        g_tutuparam.enable_gps_unit = 1;
    }

#if 0    
    if(!g_tutugps.is_enable()){
         g_tutugps.enable_gps();
    }
#endif

    tutucore_hold_gps(180);
    // 允许进入立即定位代码一次 
    g_tutuparam.flag_enter_gps_pos_code = 2;
    g_tutuparam.flag_enter_wifi_pos_code = 1;
    g_tutuparam.flag_enter_lbs_pos_code = 1;

    xlx_action_reply(success,data);
}

// 检查设备升级 
void xlx_action_checkupgrade(xlx_action_data *data){
    xlx_action_reply(1,data);

    // fota服务器ip 
    if(data->argc >=2){
        if(1 == xlx_str_is_ip(data->argv[1])){// 如果是ip 
            memset(g_tutuparam.fota_ipaddr,0,15);
            xlx_strcopy(g_tutuparam.fota_ipaddr,15,data->argv[1]);
        }else{
            g_tutuos.getaddress(data->argv[1],g_tutuparam.fota_ipaddr,16);
        }
    }

    // fota服务器端口号 
    if(data->argc >= 3){
        int port = 0;
        port = atoi(data->argv[2]);
        if(port > 0){
            g_tutuparam.fota_port = port;
        }
    }

    // 5s后进入升级模式 
    g_pri_fota_countdown.enable = 1;
    g_pri_fota_countdown.time = 5;
}

// 开关网络功能 
void xlx_action_enablenet(xlx_action_data *data){
    if(data->argc >= 2){
        char rspbuf[32] = {0};
        if(xlx_action_check_permission(data->t) == 1){
            sprintf(rspbuf,"EnableNet %s,ok\n",data->argv[1]);


            if(strcasecmp("open",data->argv[1]) == 0){
                g_tutuconfig.enable_status |= ENABLE_NET;
            }else if(strcasecmp("close",data->argv[1]) == 0){
                if((g_tutuconfig.enable_status & ENABLE_NET) != 0){
                    g_tutuconfig.enable_status ^= ENABLE_NET;
                }
            }

            sprintf(data->outbuf,"%s",rspbuf);
            return;
        }
        sprintf(rspbuf,"EnableNet %s,failt\n",data->argv[1]);
        return;
    }
    xlx_action_reply(0,data);
}

/* 飞行模式设置 
*  AT+XLX=FlyMode,进入时间,退出时间,循环模式   
*   模式= 1，进入飞行模式
*   进入时间：多少分钟后进入飞行模式    (   单位：分钟)
*   退出时间：多少分钟后退出飞行模式    (   单位：分钟)
*   循环模式：进入<--->退出 之间循环多少次      (0表示不循环)
*       设置AT+XLX=FlyMode,1,0,0     开启飞行模式，1分钟进入，不循环
*       取消 AT+XLX=FlyMode,0,0,0    关闭飞行模式
*/
void xlx_action_flymode(xlx_action_data *data){
    int success = 0;

    if(xlx_action_check_permission(data->t) == 1 && data->argc >=4){
        int enter_time = atoi(data->argv[1]);
        int exit_time = atoi(data->argv[2]);
        int loop = atoi(data->argv[3]);

        g_tutuconfig.fly_mode.counter = loop;
        g_tutuconfig.fly_mode.enter_time = enter_time;
        g_tutuconfig.fly_mode.exit_time = exit_time;

        // 如果都是0，表示取消飞行模式 
        if(loop == 0 && enter_time == 0 && exit_time == 0){
            // 禁用飞行模式 
            g_tutuconfig.fly_mode.enable = 0;
            // 流程步骤置零 
            g_tutuconfig.fly_mode.step = 0;

        }else{
            // 激活飞行模式 
            g_tutuconfig.fly_mode.enable = 1;
            // 流程步骤置零 
            g_tutuconfig.fly_mode.step = 0;
            

        }

        tutu_save_config_flag = 1;
        success = 1;
    }

    xlx_action_reply(success,data);
    
}

/**
 * 短信唤醒功能
 * 设备不需要回复，只需要联网上线即可
*/
void xlx_action_wekup(xlx_action_data *data){
    *(data->outbuf) = '\0';
    data->reply = ACTION_REPLY_NO;

    if(data->t == ACTION_TYPE_SMS){
         
        g_tutuparam.net_once_hold_time = 300;// 默认激活网络300s 

        if(data->argc > 1){
            g_tutuparam.net_once_hold_time = atoi(data->argv[1]);
        }

        // 唤醒，联网立马上传心跳和位置 
        g_tutuparam.flag_enter_gps_pos_code = 1;
        g_tutuparam.flag_enter_heart_code = 1;

        g_tutuparam.network_restart_cfg.enable = 1;
        g_tutuparam.network_restart_cfg.time = 2;
        g_tutuparam.network_restart_cfg.check_counter = 0;
    }
}

// 设置录音文件单个文件录制时长 
void xlx_action_setaudiofile(xlx_action_data *data){
    int success = 0;

    if(data->argc >= 2){
        if(xlx_action_check_permission(data->t) == 1){
            int longtime = atoi(data->argv[1]);
            
            if (longtime < 0) {
                longtime = 15;
            } else if (longtime > 60) {
                longtime = 60;
            }

#ifdef TUTU_CODE_EC618_BSJ
            if (longtime > 15) {
                longtime = 15;
            }
#endif

            g_tutuconfig.audio_mode.file_longtime = longtime;
            tutu_save_config_flag = 1;

            success = 1;
        }
    }

    xlx_action_reply(success,data);
}


/**
 * 切换模式
 */
void xlx_action_switchmode(xlx_action_data *data){
    int success = 0;
    // int mode = 0;

    if(data->argc > 1){
        // mode = atoi(data->argv[1]);

        tutu_save_config_flag = 1;
        success = 1;
    }

    xlx_action_reply(success,data);
}

// 设置录音文件码率 
void xlx_action_setaudiobitrate(xlx_action_data *data){
    int success = 0;
    int mode = 0;
    if(data->argc > 1){
        mode = atoi(data->argv[1]);
        if(mode >=0 && mode <=7){
            g_tutuconfig.audio_bitrate = mode;

            tutu_save_config_flag = 1;
            success = 1;
        }
    }

    xlx_action_reply(success,data);
}

//开启震动后自动采集gps
void xlx_action_shakegps(xlx_action_data* data) {
    int success = 0;
    if (data->argc > 1) {
        if (strcasecmp("open", data->argv[1]) == 0) {
            g_tutuconfig.shake_auto_open_gps = 1;
        }
        else {
            g_tutuconfig.shake_auto_open_gps = 0;
        }
        success = 1;
    }
    xlx_action_reply(success, data);
}

/**
 * 给设备写imei
 * Login,123456,30
 * WriteImei,XXX(14位imei)
 * 
 */
void xlx_action_writeimei(xlx_action_data *data){
    int success = 0;

    // 该指令不支持at操作 
    if((data->t == ACTION_TYPE_SMS || data->t == ACTION_TYPE_WEB) && data->argc > 1){
        if(strlen(data->argv[1]) == 15){
            success = 1;
            // 10s后重启设备 
            g_tutuparam.restart_cfg.enable = 1;
            g_tutuparam.restart_cfg.time = 10;
        }
    }

    xlx_action_reply(success,data);
}

// 开启网络日志 
void xlx_action_netlog(xlx_action_data *data){
    int success = 0;
    int status = 0;
    if(data->argc > 1){
        // 开启网络日志 
        status = atoi(data->argv[1]);
        tutu_net_logger = status;
        success = 1;

        if(data->argc > 2){
            // 日志级别 
            status = atoi(data->argv[2]);
            tutu_net_logger_level = status;
        }
        
        if(tutu_net_logger != 1){
            // 如果关闭网络日志，则重启一次机器，释放内存碎片 
            // 5s后重启设备 
            g_tutuparam.restart_cfg.enable = 1;
            g_tutuparam.restart_cfg.time = 5;
        }
    }
    xlx_action_reply(success,data);
}

void xlx_action_gpslog(xlx_action_data *data){
    int success = 0;
    int status = 0;
    if(data->argc > 1){
        // 开启gps原始数据日志 
        status = atoi(data->argv[1]);

        if(status == 1){
            tutu_gps_logger = 1;
        }else{
            tutu_gps_logger = 0;
        }
        success = 1;
    }
    xlx_action_reply(success,data);
}

void xlx_action_gsensorlog(xlx_action_data *data){
    int success = 0;
    // int status = 0;
    if(data->argc > 1){
        // 开启gsensor原始数据日志 
        // status = atoi(data->argv[1]);
        success = 1;
    }
    xlx_action_reply(success,data);
}

/*
* log
*/
void xlx_action_showlog(xlx_action_data *data){
    int success = 0;
    int status = 0;
    if(data->argc > 1){
        // 开启日志 
        status = atoi(data->argv[1]);

        if(status == 1){
            tutu_show_logger = 1;
        }else{
            tutu_show_logger = 0;
        }
        if (g_tutuos.uart_log_enable) {
            g_tutuos.uart_log_enable(tutu_show_logger);
        }
        success = 1;
    }
    else {
        sprintf(data->outbuf,"Log: %s", tutu_show_logger?"ON":"OFF");
    }
    xlx_action_reply(success,data);
}

// 返回光感状态信息 
void xlx_action_lightinfo(xlx_action_data *data){
    char v = 126;
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"LightInfo %d\n",(int)v);
    if (tutu_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
}

// 查看iccid 
void xlx_action_geticcid(xlx_action_data *data){
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"GetICCID %s\n", TEST_ICCID);
    if (tutu_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
}

// 测试模式 
void tutucation_testmode(xlx_action_data *data){
    if(data->t == ACTION_TYPE_AT){
        if(data->argc >= 2){
            if(strcasecmp("enter",data->argv[1]) == 0){
                tutu_factory_test_mode = 1;
                tutu_show_logger = 1;
            } else { 
                if (!g_pri_power_countdown.enable) {    //测试模式，且有倒计时，则不关闭日志打印
                    tutu_show_logger = 0;
                }
                tutu_factory_test_mode = 0;
            }

            if (g_tutuos.uart_log_enable) { 
                g_tutuos.uart_log_enable(tutu_show_logger);
            }

            if (data->outbuf) {
                snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"TestMode mode=%d\n",tutu_factory_test_mode);
                TUTU_LOGI(TAG, "%s", data->outbuf);
            }
        }
    }
}


// 是否能测试 
void xlx_action_testcan(xlx_action_data *data){
    static char enable = 0;
    if(data->t == ACTION_TYPE_AT){
        if(data->argc >=2){
            enable = 1;
        }
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"TestCan enable=%d\n",enable);
        if (tutu_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
    }
}

// 测试震动次数 
void xlx_action_testshake(xlx_action_data *data){
    if(data->t == ACTION_TYPE_AT){
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"TestShake count=%d\n",0);
        if (tutu_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
    }
}

// 测试声控麦克 
void xlx_action_testmicirq(xlx_action_data *data){
    if(data->t == ACTION_TYPE_AT){
        snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"TestMicIrq count=%d\n",0);
        if (tutu_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
    }
}


// 开始麦克风测试 
void xlx_action_testmicstart(xlx_action_data *data){
    if(data->t == ACTION_TYPE_AT){
        // g_tutuaudio.start_record_pcm(NULL);
        xlx_action_reply(1,data);
    }
}

// 停止麦克风测试 
void xlx_action_testmicstop(xlx_action_data *data){
    if(data->t == ACTION_TYPE_AT){
        // g_tutuaudio.stop_record_pcm();
        xlx_action_reply(1,data);
    }
}

void xlx_action_testcheckrf(xlx_action_data *data) {
    if(data->t == ACTION_TYPE_AT){
        // char status = g_tuturil.check_rf_state();
        TUTU_LOGI(TAG, "Test check Rf: %d", 1);
        if (1) {
            snprintf(data->outbuf, AT_CMD_OUT_BUFF_SIZE_MAX, "*CALINFO: LteCal,PASS_%d\n", 1);
        } else {
            snprintf(data->outbuf, AT_CMD_OUT_BUFF_SIZE_MAX, "CALINFO: LteCal\n");
        }
        if (tutu_factory_test_mode) TUTU_LOGI(TAG, "%s", data->outbuf);
    } else {
        TUTU_LOGI(TAG, "No at cmd");
    }
}

void xlx_action_testwifi(xlx_action_data *data) {
    if(data->t == ACTION_TYPE_AT) {
#if 0
        TutuMsgWifi *item = g_tutuwifi.get_list_index(0);
        if (!item) {
            g_tutuparam.flag_enter_wifi_pos_code = 1;
        }
        if (item) {
            for (int i = 0; i < g_tutuwifi.get_list_size() && i < 6; i++) {
                TutuMsgWifi *item = g_tutuwifi.get_list_index(i);
                char *tmp_out_buff = NULL;
                tmp_out_buff = TUTUAlloc(AT_CMD_OUT_BUFF_SIZE_MAX);
                if(NULL != tmp_out_buff){
                    memset(tmp_out_buff, 0, AT_CMD_OUT_BUFF_SIZE_MAX);
                    memcpy(tmp_out_buff,  data->outbuf, AT_CMD_OUT_BUFF_SIZE_MAX);
                    snprintf(data->outbuf, AT_CMD_OUT_BUFF_SIZE_MAX, "%s*WIFICELLINFO: \"%s\",%d,%d\n", tmp_out_buff, item->ssid, item->ssid_len, item->signal);
                    TUTUFree(tmp_out_buff);
                }
            }
        } else 
#endif        
        {
            snprintf(data->outbuf, AT_CMD_OUT_BUFF_SIZE_MAX, "*WIFICELLINFO: ,0, 0\n");     //注意格式，勿修改
        }
        if (tutu_factory_test_mode && data->outbuf) TUTU_LOGI(TAG, "%s", data->outbuf);
    }
}

// 关闭设备电源 
void xlx_action_gameover(xlx_action_data *data){
    if(data->t == ACTION_TYPE_AT){
        g_pri_power_countdown.time = 30;
        if(data->argc > 1){
            g_pri_power_countdown.time = atoi(data->argv[1]);
        }
        g_pri_power_countdown.enable = 1;
        xlx_action_reply(1,data);
    }
}

// 获取电话白名单列表 
void xlx_action_getwhite(xlx_action_data *data){

    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"GetWhite %s,%s,%s,%s,%s\n",
        g_tutuconfig.white_phonenum[0],
        g_tutuconfig.white_phonenum[1],
        g_tutuconfig.white_phonenum[2],
        g_tutuconfig.white_phonenum[3],
        g_tutuconfig.white_phonenum[4]
    );
}

// 获取sos列表 
void xlx_action_getsos(xlx_action_data *data){

    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"GetSOS %s,%s,%s,%s,%s\n",
        g_tutuconfig.sos_phonenum[0],
        g_tutuconfig.sos_phonenum[1],
        g_tutuconfig.sos_phonenum[2],
        g_tutuconfig.sos_phonenum[3],
        g_tutuconfig.sos_phonenum[4]
    );
}


// 找车，唤醒车辆闪烁 
void xlx_action_findcar(xlx_action_data *data){
    #ifdef TUTU_CODE_ASR_L342
       extern void tutu_find_my_car(void);
       tutu_find_my_car();
    #endif
    xlx_action_reply(1,data);
}

// 删除tutu_xx.cfg所有配置文件 
void xlx_action_clearcfg(xlx_action_data *data){
    tutuconfig_delall_file();

    // 6s后重启设备 
    g_tutuparam.restart_cfg.enable = 1;
    g_tutuparam.restart_cfg.time = 6;

    xlx_action_reply(1,data);
}

// 获取电池信息 
void xlx_action_getbattery(xlx_action_data *data){
    // unsigned int bat = g_tutubattery.get_battery_voltage();

    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"GetBattery mV=%d,p=%d,charge=%d,usb=%d\n",
        3986,   // bat,
        100,    //g_tutubattery.get_vol_power(),
        1,      //g_tutubattery.get_charge_status(),
        1      //g_tutubattery.has_connect_usb()
    );
}

// 刷新，立马上报心跳和设备状态到服务器 
void xlx_action_refresh(xlx_action_data *data){
    g_tutuparam.flag_enter_heart_code = 1;
    g_tutuparam.up_sync_status_counter = 3;
    xlx_action_reply(1,data);
}

// 设置低电报警阈值 
// AT+XLX=SetLowVoltage,30
void xlx_action_lowvoltage(xlx_action_data *data){
    int success = 0;
    if(data->argc > 1){
        int v = 10;
        // 电压值 
        v = atoi(data->argv[1]);
        if(v > 0){
            g_tutuconfig.low_voltage_threshold = v;
            tutu_save_config_flag = 1;
            success = 1;
        }        
    }
    else if(data->argc == 1){
        sprintf(data->outbuf, "LowVoltageThreshold=%d",g_tutuconfig.low_voltage_threshold);
        return;
    }
    xlx_action_reply(success,data);
}

// 开启rtmp 拉流
// AT+XLX=RtmpStopPull
void xlx_action_rtmppull(xlx_action_data *data){
    int success = 0;
    if(search_sub_str_position ("rtmp://", data->argv[1]) > 0){
        // tutu_rtmp_pull_service_init(data->argv[1]);
        success = 1;
    }
    xlx_action_reply(success,data);    
}

// 关闭 rtmp 拉流
// AT+XLX=RtmpPull,rtmp://livepull.tutuiot.com/zax/861082079313132?auth_key=1716277690-0-0-bda9e0d5c2719975569585cbecc64ad9
// AT+XLX=RtmpPull,rtmp://livepull.tutuiot.com/zax/861082079313272_0?auth_key=1716361477-0-0-2ea372bbe3a36c671a8c727aa89704f6
void xlx_action_RtmpStopPull(xlx_action_data *data){
    int success = 0;
    if(data->argc == 1){
        // tutu_rtmp_pull_stop();
        success = 1;
    }
    xlx_action_reply(success,data);    
}

// 开启rtmp推送 
/*
* "指令内容":"RtmpOpen,rtmp://livepush.tutuiot.com/zax/861082079313132?auth_key=1717028823-0-0-b4d7155c07c5cab76fa683792e3bd223,42311C29C1F410B3A5491BD22D9E73B3,rtmp://livepull.tutuiot.com/zax/861082079313132_16?auth_key=1717028813-0-0-fe33a7cd1e0218acbed8072b5f792359",
* 参数1：   rtmp推流地址
* 参数2：   客户端ID    (42311C29C1F410B3A5491BD22D9E73B3)
* 参数3：   rtmp拉流地址
*/
void xlx_action_rtmpopen(xlx_action_data *data){
    int success = 0;
    if(data->t == ACTION_TYPE_WEB && data->argc > 1  ){
        int code = 0;
        
        #ifdef TUTU_RTMP_ENABLE
            if(data->argc>=4){
                // 有拉流
                if(strncmp(data->argv[1],"rtmp://",7) == 0){
                    TUTU_LOGI(TAG, "rtmpopen: push OK");
                    code = tutu_rtmp_open(data->argv[1],data->argv[2]);
                }
                else {
                    TUTU_LOGI(TAG, "rtmpopen: push error");
                }

                if(data->argc>=4){
                    if(strncmp(data->argv[3],"rtmp://",7) == 0){
                        TUTU_LOGI(TAG, "rtmpopen: pull OK");
                        tutu_rtmp_pull_service_init(data->argv[3]);
                    }
                    else{
                        TUTU_LOGI(TAG, "rtmpopen: pull error");
                    }
                }                
            }
            else  if(data->argc ==1){   // 只有推流
                // 有拉流
                if(strncmp(data->argv[1],"rtmp://",7) == 0){
                    TUTU_LOGI(TAG, "rtmpopen: push OK");
                    code = tutu_rtmp_open(data->argv[1],NULL);
                }
                else {
                    TUTU_LOGI(TAG, "rtmpopen: push error");
                }
            }

        #else
            snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"RtmpOpen not support!\n");
            return;
        #endif
        
        if(1 == code){
            success = 1;
            
            // // 关闭录音 
            // g_tutuconfig.audio_mode.mode = 0;
            // // 发送设备状态同步到服务器 
            // tutuapi_send_device_status_msg();
        }else if(2 == code){
            snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"RtmpOpen busy\n");
            return;
        }
    }
    xlx_action_reply(success,data);
}

// 关闭rtmp推送 
void xlx_action_rtmpclose(xlx_action_data *data){
    int success = 1;
#ifdef TUTU_RTMP_ENABLE
    tutu_rtmp_close();
    tutu_rtmp_pull_stop();
#endif
    xlx_action_reply(success,data);
}

// 查询rtmp基本信息及状态 
void xlx_action_rtmpinfo(xlx_action_data *data){
#ifdef TUTU_RTMP_ENABLE
    snprintf(data->outbuf,AT_CMD_OUT_BUFF_SIZE_MAX,"RtmpInfo,state=%d,time=%lu,url=%s\n",
        tutu_rtmp_getstate(),
        tutu_rtmp_get_validtime(),
        tutu_rtmp_geturl()
    );
#endif
}

// rtmp续期，不续期则到期后自动断开推送 
void xlx_action_rtmpvalid(xlx_action_data *data){
    int success = 0;
    if(data->argc > 1){
        int t = 0;
        t = atoi(data->argv[1]);
        if(t > 0){
#ifdef TUTU_RTMP_ENABLE
            tutu_rtmp_set_validtime(t);// 单位：秒
#endif
            success = 1;
        }
    }
    xlx_action_reply(success,data);
}

void tutu_set_auto_poweroff_time(unsigned int delay){
    g_pri_power_countdown.enable = 1;
    g_pri_power_countdown.time = delay;
}

// 指令任务帧，用来帮助执行延迟任务 
void xlx_action_task_frame(void){
    // fota升级倒计时 
    if(g_pri_fota_countdown.enable == 1){
        if(g_pri_fota_countdown.time <= 0){
            g_pri_fota_countdown.enable = 0;
            // 执行ota 
            // tutu_fota_enter();
        }
        g_pri_fota_countdown.time--;
    }

    // 重启设备倒计时 
    if(g_pri_restart_countdown.enable == 1){
        if(g_pri_restart_countdown.time <= 0){
            g_pri_restart_countdown.enable = 0;

            // 执行关机 
            g_tutuos.restart();
        }
        g_pri_restart_countdown.time--;
    }


    // 关闭设备倒计时 
    if(g_pri_power_countdown.enable == 1){
        if(g_pri_power_countdown.time <= 0){
            g_pri_power_countdown.enable = 0;

            // 执行关机 
            g_tutuos.power_off();
        }
        g_pri_power_countdown.time--;
    }    
}

